#region Using Statements
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

//using Ghosts;
#endregion

namespace OrigPacman
{
    class GhostMethods
    {
        #region ghost data
        Texture2D redGhost;
        Texture2D blueGhost;
        Texture2D purpleGhost;
        Texture2D greenGhost;
        public List<Ghosts.ghostProperty> listOfGhosts;
        public List<Map.Waypoints> listWayPoints;
        Random rand;
        // Specify file, instructions, and privelegdes
        //FileStream file = new FileStream("logging.txt", FileMode.Create, FileAccess.Write);
        //StreamWriter sw;
        Map.Waypoints tmpWay; //tmp variable for waypoints
        #endregion

        public GhostMethods() 
        {
            listOfGhosts = new List<Ghosts.ghostProperty>();
            listOfGhosts.Add(new Ghosts.ghostProperty(Ghosts.ghostProperty.Colors.BLUE, new Vector2(100, 100)));
            listOfGhosts.Add(new Ghosts.ghostProperty(Ghosts.ghostProperty.Colors.GREEN, new Vector2(200, 200)));
            listOfGhosts.Add(new Ghosts.ghostProperty(Ghosts.ghostProperty.Colors.PURPLE, new Vector2(300, 300)));
            listOfGhosts.Add(new Ghosts.ghostProperty(Ghosts.ghostProperty.Colors.RED, new Vector2(400, 400)));

            listWayPoints = new List<Map.Waypoints>();
            rand = new Random();
        }


        #region ghost methods
        public void UpdateGhosts(float elapsed, Vector2 pacPosition)
        {
            foreach (Ghosts.ghostProperty a in listOfGhosts)
            {

                //If not at waypoint just update position and move to next
                //Ghost
                if (a.currentDirection == getDirectionToWaypoint(a.Position, a.nextWayPoint) && a.currentDirection != Ghosts.ghostProperty.Direction.STOP)
                {
                    normalUpdate(a, elapsed);
                }
                else
                {
                    // sw.Write(a.nextWayPoint);
                    tmpWay = (Map.Waypoints)listWayPoints[a.nextWayPoint];
                    Vector2 length = (tmpWay.Position - a.Position);
                    float distance = length.Length();
                    int value;
                    value = rand.Next(99);
                    //This is in here so the AI can be made random between a wise and a random
                    //decision
                    if (value < 100)
                    {

                        //First check to see if it can continue in the same direction if the random number is between 1 and 25
                        if (value < 50)
                        {
                            //Check to see if ghost can continue in same direction
                            switch (a.currentDirection)
                            {
                                case Ghosts.ghostProperty.Direction.EAST:
                                    if (tmpWay.Right < listWayPoints.Count - 1)
                                    {
                                        int tmp = a.nextWayPoint;
                                        a.nextWayPoint = tmpWay.Right;
                                        a.prevWayPoint = tmp;

                                        a.Position = new Vector2(tmpWay.Position.X + distance + (a.speed * elapsed), tmpWay.Position.Y);
                                        continue;
                                    }
                                    break;
                                case Ghosts.ghostProperty.Direction.NORTH:
                                    if (tmpWay.Up < listWayPoints.Count - 1)
                                    {
                                        int tmp = a.nextWayPoint;
                                        a.nextWayPoint = tmpWay.Up;
                                        a.prevWayPoint = tmp;
                                        a.Position = new Vector2(tmpWay.Position.X, tmpWay.Position.Y - (distance + (a.speed * elapsed)));
                                        continue;
                                    }
                                    break;
                                case Ghosts.ghostProperty.Direction.SOUTH:
                                    if (tmpWay.Down < listWayPoints.Count - 1)
                                    {
                                        int tmp = a.nextWayPoint;
                                        a.nextWayPoint = tmpWay.Down;
                                        a.prevWayPoint = tmp;
                                        a.Position = new Vector2(tmpWay.Position.X, tmpWay.Position.Y + distance + (a.speed * elapsed));
                                        continue;
                                    }
                                    break;
                                case Ghosts.ghostProperty.Direction.WEST:
                                    if (tmpWay.Left < listWayPoints.Count - 1)
                                    {
                                        int tmp = a.nextWayPoint;
                                        a.nextWayPoint = tmpWay.Left;
                                        a.prevWayPoint = tmp;
                                        a.Position = new Vector2(tmpWay.Position.X - (distance + (a.speed * elapsed)), tmpWay.Position.Y);
                                        continue;
                                    }
                                    break;
                            }//End switch
                        }
                        //If not move in a random direction
                        //Random Move
                        value = rand.Next(0, 3);
                        switch (value)
                        {
                            case 0://Move WEST
                                if (tmpWay.Left < 90)
                                {
                                    int tmp = a.nextWayPoint;
                                    a.nextWayPoint = tmpWay.Left;
                                    a.prevWayPoint = tmp;
                                    a.currentDirection = Ghosts.ghostProperty.Direction.WEST;
                                }
                                else //Pick another direction
                                {
                                    a.currentDirection = getNextDirection(a.currentDirection);
                                    while (!tryNextDirection(a, a.currentDirection))
                                    {
                                        a.currentDirection = getNextDirection(a.currentDirection);
                                    }
                                    setNewPoints(a);
                                }
                                break;
                            case 1: //EAST
                                if (tmpWay.Right < 90)
                                {
                                    int tmp = a.nextWayPoint;
                                    a.nextWayPoint = tmpWay.Right;
                                    a.prevWayPoint = tmp;
                                    a.currentDirection = Ghosts.ghostProperty.Direction.EAST;
                                }
                                else
                                {
                                    a.currentDirection = getNextDirection(a.currentDirection);
                                    while (!tryNextDirection(a, a.currentDirection))
                                    {
                                        a.currentDirection = getNextDirection(a.currentDirection);
                                    }
                                    setNewPoints(a);
                                }
                                break;
                            case 2:  //South
                                if (tmpWay.Down < 90)
                                {
                                    int tmp = a.nextWayPoint;
                                    a.nextWayPoint = tmpWay.Down;
                                    a.prevWayPoint = tmp;
                                    a.currentDirection = Ghosts.ghostProperty.Direction.SOUTH;
                                }
                                else
                                {
                                    a.currentDirection = getNextDirection(a.currentDirection);
                                    while (!tryNextDirection(a, a.currentDirection))
                                    {
                                        a.currentDirection = getNextDirection(a.currentDirection);
                                    }
                                    setNewPoints(a);
                                }
                                break;
                            case 3:
                                if (tmpWay.Up < 90)
                                {
                                    int tmp = a.nextWayPoint;
                                    a.nextWayPoint = tmpWay.Up;
                                    a.prevWayPoint = tmp;
                                    a.currentDirection = Ghosts.ghostProperty.Direction.NORTH;
                                }
                                else
                                {
                                    a.currentDirection = getNextDirection(a.currentDirection);
                                    while (!tryNextDirection(a, a.currentDirection))
                                    {
                                        a.currentDirection = getNextDirection(a.currentDirection);
                                    }
                                    setNewPoints(a);
                                }
                                break;
                        }//End Switch


                    }//End if

                }
            }

        }
        public void RenderGhosts(ref SpriteBatch sprite)
        {
            int x = 0;
            int y = 0;
            foreach (Ghosts.ghostProperty a in listOfGhosts)
            {
                switch (a.Color)
                {
                    case Ghosts.ghostProperty.Colors.BLUE:
                        x = (int)a.Position.X;
                        y = (int)a.Position.Y;
                        sprite.Draw(blueGhost, new Rectangle(x, y, 32, 32), Color.White);
                        break;
                    case Ghosts.ghostProperty.Colors.GREEN:
                        x = (int)a.Position.X;
                        y = (int)a.Position.Y;
                        sprite.Draw(greenGhost, new Rectangle(x, y, 32, 32), Color.White);
                        break;
                    case Ghosts.ghostProperty.Colors.PURPLE:
                        x = (int)a.Position.X;
                        y = (int)a.Position.Y;
                        sprite.Draw(purpleGhost, new Rectangle(x, y, 32, 32), Color.White);
                        break;
                    case Ghosts.ghostProperty.Colors.RED:
                        x = (int)a.Position.X;
                        y = (int)a.Position.Y;
                        sprite.Draw(redGhost, new Rectangle(x, y, 32, 32), Color.White);
                        break;
                }//End switch
            }//End foreach

        }
        public void setWaypoints(List<Map.Waypoints> list)
        {
            listWayPoints = list;

            foreach (Ghosts.ghostProperty a in listOfGhosts)
            {
                tmpWay = listWayPoints[a.prevWayPoint];
                a.Position = tmpWay.Position;
            }
        }
        //===========================================
        //Returns Direction of Next Waypoint
        //===========================================
        private Ghosts.ghostProperty.Direction getDirectionToWaypoint(Vector2 pos, int nextWayIndex)
        {
            if (nextWayIndex > listWayPoints.Count - 1)
                return Ghosts.ghostProperty.Direction.STOP;
            tmpWay = listWayPoints[nextWayIndex];
            Vector2 vec = tmpWay.Position - pos;
            vec.Normalize();
            if (vec.X < 0.45f && vec.X > -0.45f)
            {
                vec.X = 0.0f;
            }
            if (vec.X < -0.5f)
            {
                vec.X = -1.0f;
                vec.Y = 0.0f;
            }
            if (vec.X > 0.5)
            {
                vec.X = 1.0f;
                vec.Y = 0.0f;
            }
            if (vec.Y < 0.45f && vec.Y > -0.45f)
            {
                vec.Y = 0.0f;
            }
            if (vec.Y > 0.5)
            {
                vec.Y = 1.0f;
                vec.X = 0.0f;
            }
            if (vec.Y < -0.5f)
            {
                vec.Y = -1.0f;
                vec.X = 0.0f;
            }
            if (vec.X == 1.0f)
                return Ghosts.ghostProperty.Direction.EAST;
            else if (vec.X == -1.0f)
                return Ghosts.ghostProperty.Direction.WEST;
            else if (vec.Y == 1.0f)
                return Ghosts.ghostProperty.Direction.SOUTH;
            else if (vec.Y == -1.0f)
                return Ghosts.ghostProperty.Direction.NORTH;
            return Ghosts.ghostProperty.Direction.STOP;
        }
        private Ghosts.ghostProperty.Direction reverseDirection(Ghosts.ghostProperty.Direction dir)
        {
            if (dir == Ghosts.ghostProperty.Direction.EAST)
                return Ghosts.ghostProperty.Direction.WEST;
            if (dir == Ghosts.ghostProperty.Direction.NORTH)
                return Ghosts.ghostProperty.Direction.SOUTH;
            if (dir == Ghosts.ghostProperty.Direction.SOUTH)
                return Ghosts.ghostProperty.Direction.NORTH;
            if (dir == Ghosts.ghostProperty.Direction.WEST)
                return Ghosts.ghostProperty.Direction.EAST;

            return Ghosts.ghostProperty.Direction.STOP;
        }
        private Ghosts.ghostProperty.Direction getRelativeDirection(Vector2 ghost, Vector2 pac)
        {
            //Calculate the greatest distance between pacman and ghost
            float Ydifference = pac.Y - ghost.Y;
            float Xdifference = pac.X - ghost.X;
            if (pac.Y > ghost.Y && Ydifference > Xdifference)
                return Ghosts.ghostProperty.Direction.SOUTH;
            if (pac.Y < ghost.Y && Ydifference > Xdifference)
                return Ghosts.ghostProperty.Direction.NORTH;
            if (pac.X > ghost.X && Xdifference > Ydifference)
                return Ghosts.ghostProperty.Direction.EAST;
            if (pac.X < ghost.X && Xdifference > Ydifference)
                return Ghosts.ghostProperty.Direction.WEST;
            return Ghosts.ghostProperty.Direction.WEST;
        }
        private Ghosts.ghostProperty.Direction getNextDirection(Ghosts.ghostProperty.Direction dir)
        {
            if (dir == Ghosts.ghostProperty.Direction.WEST)
                return Ghosts.ghostProperty.Direction.NORTH;
            if (dir == Ghosts.ghostProperty.Direction.NORTH)
                return Ghosts.ghostProperty.Direction.EAST;
            if (dir == Ghosts.ghostProperty.Direction.EAST)
                return Ghosts.ghostProperty.Direction.SOUTH;
            if (dir == Ghosts.ghostProperty.Direction.SOUTH)
                return Ghosts.ghostProperty.Direction.WEST;
            if (dir == Ghosts.ghostProperty.Direction.STOP)
                return Ghosts.ghostProperty.Direction.EAST;

            return Ghosts.ghostProperty.Direction.STOP;
        }
        private bool tryNextDirection(Ghosts.ghostProperty ghost, Ghosts.ghostProperty.Direction dir)
        {
            Map.Waypoints tmp = (Map.Waypoints)listWayPoints[ghost.nextWayPoint];
            switch (dir)
            {
                case Ghosts.ghostProperty.Direction.EAST:
                    if (tmp.Right < listWayPoints.Count - 1)
                        return true;
                    break;
                case Ghosts.ghostProperty.Direction.NORTH:
                    if (tmp.Up < listWayPoints.Count - 1)
                        return true;
                    break;
                case Ghosts.ghostProperty.Direction.SOUTH:
                    if (tmp.Down < listWayPoints.Count - 1)
                        return true;
                    break;
                case Ghosts.ghostProperty.Direction.WEST:
                    if (tmp.Left < listWayPoints.Count - 1)
                        return true;
                    break;
            }
            return false;
        }
        private void setNewPoints(Ghosts.ghostProperty ghost)
        {
            if (ghost.nextWayPoint > listWayPoints.Count - 1 || ghost.nextWayPoint < 0)
                return;
            Map.Waypoints tmp = (Map.Waypoints)listWayPoints[ghost.nextWayPoint];
            int prev;
            switch (ghost.currentDirection)
            {
                case Ghosts.ghostProperty.Direction.EAST:
                    prev = ghost.nextWayPoint;
                    ghost.nextWayPoint = tmp.Right;
                    ghost.prevWayPoint = prev;
                    break;
                case Ghosts.ghostProperty.Direction.NORTH:
                    prev = ghost.nextWayPoint;
                    ghost.nextWayPoint = tmp.Up;
                    ghost.prevWayPoint = prev;
                    break;
                case Ghosts.ghostProperty.Direction.SOUTH:
                    prev = ghost.nextWayPoint;
                    ghost.nextWayPoint = tmp.Down;
                    ghost.prevWayPoint = prev;
                    break;
                case Ghosts.ghostProperty.Direction.WEST:
                    prev = ghost.nextWayPoint;
                    ghost.nextWayPoint = tmp.Left;
                    ghost.prevWayPoint = prev;
                    break;
            }
        }
        private void normalUpdate(Ghosts.ghostProperty a, float elapsed)
        {
            //Update Direction
            if (a.currentDirection == Ghosts.ghostProperty.Direction.EAST)
            {
                a.Position = new Vector2(a.Position.X + (a.speed * elapsed), a.Position.Y);
            }
            if (a.currentDirection == Ghosts.ghostProperty.Direction.NORTH)
            {
                a.Position = new Vector2(a.Position.X, a.Position.Y - (a.speed * elapsed));
            }
            if (a.currentDirection == Ghosts.ghostProperty.Direction.SOUTH)
            {
                a.Position = new Vector2(a.Position.X, a.Position.Y + (a.speed * elapsed));
            }
            if (a.currentDirection == Ghosts.ghostProperty.Direction.WEST)
            {
                a.Position = new Vector2(a.Position.X - (a.speed * elapsed), a.Position.Y);
            }
        }
        public List<Ghosts.ghostProperty> getListOfGhosts()
        {
            return listOfGhosts;
        }

        #endregion
    }
}
